package auth.plugins.flutter.io.fist_local_auth;

import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;

@RestrictTo(RestrictTo.Scope.LIBRARY)
public class FingerprintDialogFragmentV2 extends DialogFragment {

    private static final String TAG = "FingerprintDialogFragmentV2";
    private static final String KEY_DIALOG_BUNDLE = "SavedBundle";

    /**
     * Error/help message will show for this amount of time.
     * For error messages, the dialog will also be dismissed after this amount of time.
     * Error messages will be propagated back to the application via AuthenticationCallback
     * after this amount of time.
     */
    protected static final int HIDE_DIALOG_DELAY = 2000; // ms

    // Shows a temporary message in the help area
    protected static final int MSG_SHOW_HELP = 1;
    // Show an error in the help area, and dismiss the dialog afterwards
    protected static final int MSG_SHOW_ERROR = 2;
    // Dismisses the authentication dialog
    protected static final int MSG_DISMISS_DIALOG_ERROR = 3;
    // Resets the help message
    protected static final int MSG_RESET_MESSAGE = 4;
    // Dismisses the authentication dialog after success.
    protected static final int MSG_DISMISS_DIALOG_AUTHENTICATED = 5;
    // The amount of time required that this fragment be displayed for in order that
    // we show an error message on top of the UI.
    protected static final int DISPLAYED_FOR_500_MS = 6;

    // States for icon animation
    private static final int STATE_NONE = 0;
    private static final int STATE_FINGERPRINT = 1;
    private static final int STATE_FINGERPRINT_ERROR = 2;
    private static final int STATE_FINGERPRINT_AUTHENTICATED = 3;
    protected static final int DISPLAYED_FOR_30_S = 7;
//    protected static final int TIME_COUNT= 8;
//    static   int recLen = 31;
//    protected static final int HIDE_DIALOG_DELAY_30S = 31000; // ms
//    public  void  setRecLen(){
//        recLen=31;
//    }
//    class MyThread implements Runnable{
//        @Override
//        public void run() {
//            while (recLen>0){
//                try {
//                    Thread.sleep(1000);
//                    mHandler.obtainMessage(FingerprintDialogFragmentV2.TIME_COUNT)
//                            .sendToTarget();
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//
//            }
//        }
//    }

//    void dismissAfterDelay30S() {
//        new Thread(new MyThread()).start();
//        mHandler.postDelayed(new Runnable() {
//            @Override
//            public void run() {
//                dismiss();
//            }
//        }, HIDE_DIALOG_DELAY_30S);
//    }
    /**
     * Creates a dialog requesting for Fingerprint authentication.
     */
    public static FingerprintDialogFragmentV2 newInstance() {
        FingerprintDialogFragmentV2 fragment = new FingerprintDialogFragmentV2();
        return fragment;
    }

    @Override
    public void show(@NonNull FragmentManager manager, @Nullable String tag) {
        FragmentTransaction ft = manager.beginTransaction();
        ft.add(this, tag);
        ft.commitAllowingStateLoss();
    }

    final class H extends Handler {
        @Override
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
                case MSG_SHOW_HELP:
                    handleShowHelp((CharSequence) msg.obj);
                    break;
                case MSG_SHOW_ERROR:
                    handleShowError(msg.arg1, (CharSequence) msg.obj);
                    break;
                case MSG_DISMISS_DIALOG_ERROR:
                    handleDismissDialogError();
                    break;
                case MSG_DISMISS_DIALOG_AUTHENTICATED:
                    dismiss();
                    break;
                case MSG_RESET_MESSAGE:
                    handleResetMessage();
                    break;
                case DISPLAYED_FOR_500_MS:
                    mDismissInstantly = false;
                    break;
                case DISPLAYED_FOR_30_S:
//                    dismissAfterDelay30S();
                    dismiss();
                    break;
//                case  TIME_COUNT:
//                    if(recLen>0){
//                        mErrorText.setTextColor(mErrorColor);
//                        mErrorText.setText("失败次数过多，请在"+(recLen-1)+"秒后尝试");
//                        recLen--;
//                    }
//                    break;
            }
        }
    }

    private FingerprintDialogFragmentV2.H mHandler = new FingerprintDialogFragmentV2.H();
    private Bundle mBundle;
    private int mErrorColor;
    private int mTextColor;
    private int mLastState;
    private ImageView mFingerprintIcon;
    private TextView mErrorText;

    private Context mContext;
    private Dialog mDialog;
    /**
     * This flag is used to control the instant dismissal of the dialog fragment. In the case where
     * the user is already locked out this dialog will not appear. In the case where the user is
     * being locked out for the first time an error message will be displayed on the UI before
     * dismissing.
     */
    protected boolean mDismissInstantly = true;

    // This should be re-set by the BiometricPromptCompat each time the lifecycle changes.
    DialogInterface.OnClickListener mNegativeButtonListener;
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
       // setupWindow(getDialog().getWindow());
    }
    private void setupWindow(Window window) {
        if (window != null) {
            WindowManager.LayoutParams lp = window.getAttributes();
            lp.gravity = Gravity.CENTER;
            lp.dimAmount = 0;
            lp.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
            window.setAttributes(lp);
            window.setBackgroundDrawableResource(R.color.bg_biometric_prompt_dialog);
            window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        }
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        if (savedInstanceState != null && mBundle == null) {
            mBundle = savedInstanceState.getBundle(KEY_DIALOG_BUNDLE);
        }
        final View layout = LayoutInflater.from(getContext())
                .inflate(R.layout.layout_biometric_prompt_dialog, container);
        RelativeLayout rootView = layout.findViewById(R.id.root_view);
        rootView.setClickable(false);
        final TextView subtitleView = layout.findViewById(R.id.fingerprint_subtitle_1);
        final TextView descriptionView = layout.findViewById(R.id.fingerprint_description_1);
        final CharSequence subtitle = mBundle.getCharSequence(
                BiometricPromptV2.KEY_SUBTITLE);
        if (TextUtils.isEmpty(subtitle)) {
            subtitleView.setVisibility(View.GONE);
        } else {
            subtitleView.setVisibility(View.VISIBLE);
            subtitleView.setText(subtitle);
        }

        final CharSequence description = mBundle.getCharSequence(
                BiometricPromptV2.KEY_DESCRIPTION);
        if (TextUtils.isEmpty(description)) {
            descriptionView.setVisibility(View.GONE);
        } else {
            descriptionView.setVisibility(View.VISIBLE);
            descriptionView.setText(description);
        }

        mFingerprintIcon = layout.findViewById(R.id.fingerprint_icon_1);
        mErrorText = layout.findViewById(R.id.fingerprint_error_1);
        mErrorText.setText(mBundle.getString( BiometricPromptV2.KEY_TITLE));

        final CharSequence negativeButtonText =
                mBundle.getCharSequence(BiometricPromptV2.KEY_NEGATIVE_TEXT);
        final TextView cancelBtn = layout.findViewById(R.id.cancel_btn);
        if (TextUtils.isEmpty(negativeButtonText)) {
            cancelBtn.setVisibility(View.GONE);
        } else {
            cancelBtn.setVisibility(View.VISIBLE);
            cancelBtn.setText(negativeButtonText);
            cancelBtn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if (mNegativeButtonListener != null) {
                        mNegativeButtonListener.onClick(getDialog(), -2);
                    }
                    dismiss();
                }
            });
        }

        return layout;
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        if (savedInstanceState != null && mBundle == null) {
            mBundle = savedInstanceState.getBundle(KEY_DIALOG_BUNDLE);
        }

        mDialog = super.onCreateDialog(savedInstanceState);

        mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
        if (mDialog.getWindow() != null) {
            mDialog.getWindow().setBackgroundDrawableResource(R.color.bg_biometric_prompt_dialog);
        }
        return mDialog;
    }

    @Override
    public void onStart() {
        super.onStart();
        DisplayMetrics dm = new DisplayMetrics();
        getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm);
        getDialog().getWindow().setLayout(dm.widthPixels, getDialog().getWindow().getAttributes().height);
        getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));

    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putBundle(KEY_DIALOG_BUNDLE, mBundle);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mContext = getContext();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            mErrorColor = getThemedColorFor(android.R.attr.colorError);
        } else {
            mErrorColor = ContextCompat.getColor(mContext, R.color.biometric_error_color);
        }
        mTextColor = getThemedColorFor(android.R.attr.textColorSecondary);
    }

    @Override
    public void onResume() {
        super.onResume();
        mLastState = STATE_NONE;
        updateFingerprintIcon(STATE_FINGERPRINT);
    }

    @Override
    public void onPause() {
        super.onPause();
        // Remove everything since the fragment is going away.
        mHandler.removeCallbacksAndMessages(null);
    }

    @Override
    public void onCancel(DialogInterface dialog) {
        super.onCancel(dialog);
        FingerprintHelperFragmentV2 fingerprintHelperFragment = (FingerprintHelperFragmentV2)
                getFragmentManager()
                        .findFragmentByTag(BiometricPromptV2.FINGERPRINT_HELPER_FRAGMENT_TAG);
        if (fingerprintHelperFragment != null) {
            fingerprintHelperFragment.cancel(FingerprintHelperFragmentV2.USER_CANCELED_FROM_USER);
        }
    }

    public void setBundle(Bundle bundle) {
        mBundle = bundle;
    }

    private int getThemedColorFor(int attr) {
        TypedValue tv = new TypedValue();
        Resources.Theme theme = mContext.getTheme();
        theme.resolveAttribute(attr, tv, true /* resolveRefs */);
        TypedArray arr = getActivity().obtainStyledAttributes(tv.data, new int[] {attr});

        final int color = arr.getColor(0 /* index */, 0 /* defValue */);
        arr.recycle();
        return color;
    }

    /**
     * The negative button text is persisted in the fragment, not in BiometricPromptCompat. Since
     * the dialog persists through rotation, this allows us to return this as the error text for
     * ERROR_NEGATIVE_BUTTON.
     */
    protected CharSequence getNegativeButtonText() {
        return mBundle.getCharSequence(BiometricPromptV2.KEY_NEGATIVE_TEXT);
    }

    /**
     * Sets the negative button listener.
     * @param listener
     */
    protected void setNegativeButtonListener(DialogInterface.OnClickListener listener) {
        mNegativeButtonListener = listener;
    }

    /**
     * Returns the handler; the handler is used by FingerprintHelperFragment to notify the UI of
     * changes from Fingerprint callbacks.
     * @return
     */
    protected Handler getHandler() {
        return mHandler;
    }

    private boolean shouldAnimateForTransition(int oldState, int newState) {
        if (oldState == STATE_NONE && newState == STATE_FINGERPRINT) {
            return false;
        } else if (oldState == STATE_FINGERPRINT && newState == STATE_FINGERPRINT_ERROR) {
            return true;
        } else if (oldState == STATE_FINGERPRINT_ERROR && newState == STATE_FINGERPRINT) {
            return true;
        } else if (oldState == STATE_FINGERPRINT && newState == STATE_FINGERPRINT_AUTHENTICATED) {
            // TODO(b/77328470): add animation when fingerprint is authenticated
            return false;
        }
        return false;
    }

    @RequiresApi(21)
    private Drawable getAnimationForTransition(int oldState, int newState) {
        int iconRes;

        if (oldState == STATE_NONE && newState == STATE_FINGERPRINT) {
            iconRes = R.drawable.fingerprint_dialog_fp_to_error;
        } else if (oldState == STATE_FINGERPRINT && newState == STATE_FINGERPRINT_ERROR) {
            iconRes = R.drawable.fingerprint_dialog_fp_to_error;
        } else if (oldState == STATE_FINGERPRINT_ERROR && newState == STATE_FINGERPRINT) {
            iconRes = R.drawable.fingerprint_dialog_error_to_fp;
        } else if (oldState == STATE_FINGERPRINT
                && newState == STATE_FINGERPRINT_AUTHENTICATED) {
            // TODO(b/77328470): add animation when fingerprint is authenticated
            iconRes = R.drawable.fingerprint_dialog_error_to_fp;
        } else {
            return null;
        }
        return mContext.getDrawable(iconRes);
    }

    private void updateFingerprintIcon(int newState) {
        // Devices older than this do not have FP support (and also do not support SVG), so it's
        // fine for this to be a no-op. An error is returned immediately and the dialog is not
        // shown.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            Drawable icon = getAnimationForTransition(mLastState, newState);
            if (icon == null) {
                return;
            }

            final AnimatedVectorDrawable animation = icon instanceof AnimatedVectorDrawable
                    ? (AnimatedVectorDrawable) icon
                    : null;

            mFingerprintIcon.setImageDrawable(icon);
            if (animation != null && shouldAnimateForTransition(mLastState, newState)) {
                animation.start();
            }

            mLastState = newState;
        }
    }

    void handleShowHelp(CharSequence msg) {
        updateFingerprintIcon(STATE_FINGERPRINT_ERROR);
        mHandler.removeMessages(MSG_RESET_MESSAGE);
        mErrorText.setTextColor(mErrorColor);
       // mErrorText.setText(msg);
        mErrorText.setText(mBundle.getString(BiometricPromptV2.KEY_FAIL_HINT));

        // Reset the text after a delay
        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_RESET_MESSAGE), HIDE_DIALOG_DELAY);
    }

    void handleShowError(int errMsgId, CharSequence msg) {
        updateFingerprintIcon(STATE_FINGERPRINT_ERROR);
        mHandler.removeMessages(MSG_RESET_MESSAGE);
        mErrorText.setTextColor(mErrorColor);
       // mErrorText.setText(msg);
        mErrorText.setText(mBundle.getString(BiometricPromptV2.KEY_FAIL_HINT));

        // Dismiss the dialog after a delay
        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_DISMISS_DIALOG_ERROR),
                HIDE_DIALOG_DELAY);
    }

    void dismissAfterDelay() {
        mErrorText.setTextColor(mErrorColor);
        mErrorText.setText(
                R.string.fingerprint_error_lockout);
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                dismiss();
            }
        }, HIDE_DIALOG_DELAY);
    }

    void handleDismissDialogError() {
        if (mDismissInstantly) {
            dismiss();
        } else {
            dismissAfterDelay();
        }
        // Always set this to true. In case the user tries to authenticate again the UI will not be
        // shown.
        mDismissInstantly = true;
    }

    void handleResetMessage() {
        updateFingerprintIcon(STATE_FINGERPRINT);
        mErrorText.setTextColor(mTextColor);
        mErrorText.setText(mBundle.getString(BiometricPromptV2.KEY_FAIL_HINT));
    }
}
